using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using NSMBe4;

namespace MKDS_Course_Editor
{
    public partial class TEXS_ : Form
    {
        TEXS sp;
        BackgroundWorker bwr = null;
        Color[] palette = new Color[256];
        Color[] palette_org = new Color[256];
        string file;
        public TEXS_(string file)
        {
            this.file = file;
            InitializeComponent();
            int colorNum = 0;
            for (int r = 0; r < 256; r += 256 / 8)
                for (int g = 0; g < 256; g += 256 / 8)
                    for (int b = 0; b < 256; b += 256 / 4)
                        palette[colorNum++] = Color.FromArgb(r, g, b);
            palette_org = palette;
        }

        private void spa_Load(object sender, EventArgs e)
        {
            EndianBinaryReader er = new EndianBinaryReader(new MemoryStream(File.ReadAllBytes(file)), Endianness.LittleEndian);
            sp = new TEXS();
            bool found = false;
            int startpos = 0;
            while (er.BaseStream.Length - er.BaseStream.Position != 4)
            {
                sp.Magic = er.ReadString(Encoding.ASCII, 4);
                if (sp.Magic == "TEXS") // "TEX0"
                {
                    startpos = (int)er.BaseStream.Position-4;
                    found = true;
                    break;
                }
            }
            er.BaseStream.Position = 0;
            sp.before = er.ReadBytes(startpos);
            er.ReadBytes(4);
            if (sp.Magic == "TEXS" && found == true)
            {
                sp.Length = er.ReadInt32();
                sp.Unknown1 = er.ReadInt16();
                sp.Unknown2 = er.ReadInt16();
                sp.NrTex = er.ReadInt32();
                sp.TEXO = new TEXS.TEXo[sp.Unknown1];
                sp.IMGO = new TEXS.IMGo[sp.Unknown1];
                sp.PLTO = new TEXS.PLTo[sp.Unknown2];
                sp.order = new List<int>();
                int nrTEXO = 0;
                int nrIMGO = 0;
                int nrPLTO = 0;
                while(er.BaseStream.Position!=startpos+sp.Length+8)
                {
                    switch (er.ReadString(Encoding.ASCII, 4))
                    {
                        case "TEXO":
                            sp.TEXO[nrTEXO].Magic = "TEXO";
                            sp.TEXO[nrTEXO].Lenght = er.ReadInt32();
                            er.ReadBytes(8);
                            sp.TEXO[nrTEXO].NameMagic1 = er.ReadString(Encoding.ASCII, 4);
                            sp.TEXO[nrTEXO].Stringlength1 = er.ReadInt32();
                            sp.TEXO[nrTEXO].TexName = er.ReadString(Encoding.ASCII, sp.TEXO[nrTEXO].Stringlength1);
                            sp.TEXO[nrTEXO].NameMagic2 = er.ReadString(Encoding.ASCII, 4);
                            if (sp.TEXO[nrTEXO].NameMagic2 == "NAME")
                            {
                                sp.TEXO[nrTEXO].Stringlength2 = er.ReadInt32();
                                sp.TEXO[nrTEXO].PalName = er.ReadString(Encoding.ASCII, sp.TEXO[nrTEXO].Stringlength1);
                            }
                            else
                            {
                                er.BaseStream.Position -= 4;
                            }
                            listBox1.Items.Add(sp.TEXO[nrTEXO].TexName);
                            nrTEXO += 1;
                            sp.order.Add(0);
                            break;
                        case "IMGO":
                            sp.IMGO[nrIMGO].Magic = "IMGO";
                            sp.IMGO[nrIMGO].Lenght = er.ReadInt32();
                            sp.IMGO[nrIMGO].NameMagic = er.ReadString(Encoding.ASCII, 4);
                            sp.IMGO[nrIMGO].Stringlength = er.ReadInt32();
                            sp.IMGO[nrIMGO].Name = er.ReadString(Encoding.ASCII, sp.IMGO[nrIMGO].Stringlength);
                            sp.IMGO[nrIMGO].TexFormat = er.ReadInt32();
                            sp.IMGO[nrIMGO].Width = er.ReadInt16();
                            sp.IMGO[nrIMGO].Height = er.ReadInt16();
                            sp.IMGO[nrIMGO].Unknown1 = er.ReadInt16();
                            sp.IMGO[nrIMGO].Color0 = er.ReadByte();
                            sp.IMGO[nrIMGO].Unknown2 = er.ReadByte();
                            sp.IMGO[nrIMGO].imgLength = er.ReadInt32();
                            sp.IMGO[nrIMGO].spDataLength = er.ReadInt32();
                            sp.IMGO[nrIMGO].Unknown4 = er.ReadInt32();
                            sp.IMGO[nrIMGO].Image = er.ReadBytes(sp.IMGO[nrIMGO].imgLength);
                            sp.IMGO[nrIMGO].spData = er.ReadBytes(sp.IMGO[nrIMGO].spDataLength);
                            nrIMGO += 1;
                            sp.order.Add(1);
                            break;
                        case "PLTO":
                            if (sp.IMGO[nrPLTO].TexFormat == 7)
                            {
                                nrPLTO += 1;
                            }
                            sp.PLTO[nrPLTO].Magic = "PLTO";
                            sp.PLTO[nrPLTO].Lenght = er.ReadInt32();
                            sp.PLTO[nrPLTO].NameMagic = er.ReadString(Encoding.ASCII, 4);
                            sp.PLTO[nrPLTO].Stringlength = er.ReadInt32();
                            sp.PLTO[nrPLTO].Name = er.ReadString(Encoding.ASCII, sp.PLTO[nrPLTO].Stringlength);
                            sp.PLTO[nrPLTO].Pallength = er.ReadInt32();
                            sp.PLTO[nrPLTO].Unknown = er.ReadInt32();
                            sp.PLTO[nrPLTO].Pal = Tinke.Convertir.BGR555(er.ReadBytes(sp.PLTO[nrPLTO].Pallength));
                            nrPLTO += 1;
                            sp.order.Add(2);
                            break;
                    }
                }
                if (listBox1.Items.Count == 0)
                {
                    for (int i = 0; i < sp.NrTex; i++)
                    {
                        listBox1.Items.Add(i);
                    }
                }
                sp.beafter = er.ReadBytes((int)er.BaseStream.Length - (int)er.BaseStream.Position);
                er.Close();

            }
            else
            {
                //MessageBox.Show("Error");
                er.Close();
            } 
        }
        public static TEXS Read(string file)
        {
            EndianBinaryReader er = new EndianBinaryReader(new MemoryStream(File.ReadAllBytes(file)), Endianness.LittleEndian);
            TEXS sp = new TEXS();
            bool found = false;
            int startpos = 0;
            while (er.BaseStream.Length - er.BaseStream.Position != 4)
            {
                sp.Magic = er.ReadString(Encoding.ASCII, 4);
                if (sp.Magic == "TEXS") // "TEX0"
                {
                    startpos = (int)er.BaseStream.Position - 4;
                    found = true;
                    break;
                }
            }
            er.BaseStream.Position = 0;
            sp.before = er.ReadBytes(startpos);
            er.ReadBytes(4);
            if (sp.Magic == "TEXS" && found == true)
            {
                sp.Length = er.ReadInt32();
                sp.Unknown1 = er.ReadInt16();
                sp.Unknown2 = er.ReadInt16();
                sp.NrTex = er.ReadInt32();
                sp.TEXO = new TEXS.TEXo[sp.Unknown1];
                sp.IMGO = new TEXS.IMGo[sp.Unknown1];
                sp.PLTO = new TEXS.PLTo[sp.Unknown2];
                sp.order = new List<int>();
                int nrTEXO = 0;
                int nrIMGO = 0;
                int nrPLTO = 0;
                while (er.BaseStream.Position != startpos + sp.Length + 8)
                {
                    switch (er.ReadString(Encoding.ASCII, 4))
                    {
                        case "TEXO":
                            sp.TEXO[nrTEXO].Magic = "TEXO";
                            sp.TEXO[nrTEXO].Lenght = er.ReadInt32();
                            er.ReadBytes(8);
                            sp.TEXO[nrTEXO].NameMagic1 = er.ReadString(Encoding.ASCII, 4);
                            sp.TEXO[nrTEXO].Stringlength1 = er.ReadInt32();
                            sp.TEXO[nrTEXO].TexName = er.ReadString(Encoding.ASCII, sp.TEXO[nrTEXO].Stringlength1);
                            sp.TEXO[nrTEXO].NameMagic2 = er.ReadString(Encoding.ASCII, 4);
                            if (sp.TEXO[nrTEXO].NameMagic2 == "NAME")
                            {
                                sp.TEXO[nrTEXO].Stringlength2 = er.ReadInt32();
                                sp.TEXO[nrTEXO].PalName = er.ReadString(Encoding.ASCII, sp.TEXO[nrTEXO].Stringlength1);
                            }
                            else
                            {
                                er.BaseStream.Position -= 4;
                            }
                            //listBox1.Items.Add(sp.TEXO[nrTEXO].TexName);
                            nrTEXO += 1;
                            sp.order.Add(0);
                            break;
                        case "IMGO":
                            sp.IMGO[nrIMGO].Magic = "IMGO";
                            sp.IMGO[nrIMGO].Lenght = er.ReadInt32();
                            sp.IMGO[nrIMGO].NameMagic = er.ReadString(Encoding.ASCII, 4);
                            sp.IMGO[nrIMGO].Stringlength = er.ReadInt32();
                            sp.IMGO[nrIMGO].Name = er.ReadString(Encoding.ASCII, sp.IMGO[nrIMGO].Stringlength);
                            sp.IMGO[nrIMGO].TexFormat = er.ReadInt32();
                            sp.IMGO[nrIMGO].Width = er.ReadInt16();
                            sp.IMGO[nrIMGO].Height = er.ReadInt16();
                            sp.IMGO[nrIMGO].Unknown1 = er.ReadInt16();
                            sp.IMGO[nrIMGO].Color0 = er.ReadByte();
                            sp.IMGO[nrIMGO].Unknown2 = er.ReadByte();
                            sp.IMGO[nrIMGO].imgLength = er.ReadInt32();
                            sp.IMGO[nrIMGO].spDataLength = er.ReadInt32();
                            sp.IMGO[nrIMGO].Unknown4 = er.ReadInt32();
                            sp.IMGO[nrIMGO].Image = er.ReadBytes(sp.IMGO[nrIMGO].imgLength);
                            sp.IMGO[nrIMGO].spData = er.ReadBytes(sp.IMGO[nrIMGO].spDataLength);
                            nrIMGO += 1;
                            sp.order.Add(1);
                            break;
                        case "PLTO":
                            if (sp.IMGO[nrPLTO].TexFormat == 7)
                            {
                                nrPLTO += 1;
                            }
                            sp.PLTO[nrPLTO].Magic = "PLTO";
                            sp.PLTO[nrPLTO].Lenght = er.ReadInt32();
                            sp.PLTO[nrPLTO].NameMagic = er.ReadString(Encoding.ASCII, 4);
                            sp.PLTO[nrPLTO].Stringlength = er.ReadInt32();
                            sp.PLTO[nrPLTO].Name = er.ReadString(Encoding.ASCII, sp.PLTO[nrPLTO].Stringlength);
                            sp.PLTO[nrPLTO].Pallength = er.ReadInt32();
                            sp.PLTO[nrPLTO].Unknown = er.ReadInt32();
                            sp.PLTO[nrPLTO].Pal = Tinke.Convertir.BGR555(er.ReadBytes(sp.PLTO[nrPLTO].Pallength));
                            nrPLTO += 1;
                            sp.order.Add(2);
                            break;
                    }
                }
                /*if (listBox1.Items.Count == 0)
                {
                    for (int i = 0; i < sp.NrTex; i++)
                    {
                        listBox1.Items.Add(i);
                    }
                }*/
                sp.beafter = er.ReadBytes((int)er.BaseStream.Length - (int)er.BaseStream.Position);
                er.Close();

            }
            else
            {
                //MessageBox.Show("Error");
                er.Close();
            }
            return sp;
        }
        public struct TEXS
        {
            public String Magic;
            public Int32 Length;
            public Int16 Unknown1;
            public Int16 Unknown2;
            public Int32 NrTex;
            public TEXo[] TEXO;
            public IMGo[] IMGO;
            public PLTo[] PLTO;
            public List<int> order;
            public byte[] before;
            public byte[] beafter;
            public struct TEXo
            {
                public String Magic;
                public Int32 Lenght;
                public Int32 Unknown1;
                public Int32 Unknown2;
                public String NameMagic1;
                public Int32 Stringlength1;
                public String TexName;
                public String NameMagic2;
                public Int32 Stringlength2;
                public String PalName;
            }
            public struct IMGo
            {
                public String Magic;
                public Int32 Lenght;
                public String NameMagic;
                public Int32 Stringlength;
                public String Name;
                public Int32 TexFormat;
                public Int16 Width;
                public Int16 Height;
                public Int16 Unknown1;
                public byte Color0;
                public byte Unknown2;
                public Int32 imgLength;
                public Int32 spDataLength;
                public Int32 Unknown4;
                public byte[] Image;
                public byte[] spData;
            }
            public struct PLTo
            {
                public String Magic;
                public Int32 Lenght;
                public String NameMagic;
                public Int32 Stringlength;
                public String Name;
                public Int32 Pallength;
                public Int32 Unknown;
                public Color[] Pal;
            }
        }

        private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            LibNDSFormats.NSBMD.RGBA[] image = new LibNDSFormats.NSBMD.RGBA[sp.IMGO[listBox1.SelectedIndex].Height * sp.IMGO[listBox1.SelectedIndex].Width];
            int pixelnum = sp.IMGO[listBox1.SelectedIndex].Height * sp.IMGO[listBox1.SelectedIndex].Width;
            /*switch (sp.IMGO[listBox1.SelectedIndex].TexFormat)
            {
                // No Texture
                case 0:
                    //puts( "ERROR: format 0" );
                    break;
                // A3I5 Translucent Texture (3bit Alpha, 5bit Color Index)
                case 1:
                    for (int j = 0; j < pixelnum; j++)
                    {
                        int index = sp.IMGO[listBox1.SelectedIndex].Image[j] & 0x1f;
                        int alpha = (sp.IMGO[listBox1.SelectedIndex].Image[j] >> 5) & 7;
                        alpha = ((alpha * 4) + (alpha / 2)) << 3;
                        image[j].R = sp.PLTO[listBox1.SelectedIndex].Pal[index].R;
                        image[j].G = sp.PLTO[listBox1.SelectedIndex].Pal[index].G;
                        image[j].B = sp.PLTO[listBox1.SelectedIndex].Pal[index].B;
                        image[j].A = (byte)alpha;
                    }

                    break;
                // 4-Color Palette Texture
                case 2:
                    for (int j = 0; j < pixelnum; j++)
                    {
                        uint index = sp.IMGO[listBox1.SelectedIndex].Image[j / 4];
                        index = (index >> ((j % 4) << 1)) & 3;
                        image[j].R = sp.PLTO[listBox1.SelectedIndex].Pal[index].R;
                        image[j].G = sp.PLTO[listBox1.SelectedIndex].Pal[index].G;
                        image[j].B = sp.PLTO[listBox1.SelectedIndex].Pal[index].B;
                    }
                    break;
                // 16-Color Palette Texture
                case 3:
                    if (sp.IMGO[listBox1.SelectedIndex].Unknown4 != 0) sp.PLTO[listBox1.SelectedIndex].Pal[0] = Color.Transparent; // made palette entry 0 transparent
                    for (int j = 0; j < pixelnum / 2; j++)
                    {
                        int matindex = j / 2;
                        if (sp.IMGO[listBox1.SelectedIndex].Image.Length < matindex)
                            goto end;
                        int index = sp.IMGO[listBox1.SelectedIndex].Image[matindex];
                        index = (index >> ((j % 2) << 2)) & 0x0f;
                        if (sp.PLTO[listBox1.SelectedIndex].Pal == null)
                            continue;
                        if (index < 0 || index >= sp.PLTO[listBox1.SelectedIndex].Pal.Length)
                            continue;
                        if (j < 0 || j >= pixelnum)
                            continue;
                        image[j].R = sp.PLTO[listBox1.SelectedIndex].Pal[index].R;
                        image[j].G = sp.PLTO[listBox1.SelectedIndex].Pal[index].G;
                        image[j].B = sp.PLTO[listBox1.SelectedIndex].Pal[index].B;
                    }
                    break;
                // 256-Color Palette Texture
                case 4:
                    //if (mat.color0 != 0) mat.paldata[0] = RGBA.Transparent; // made palette entry 0 transparent
                    // made palette entry 0 transparent
                    for (int j = 0; j < pixelnum; j++)
                    {
                        image[j].R = sp.PLTO[listBox1.SelectedIndex].Pal[sp.IMGO[listBox1.SelectedIndex].Image[j]].R;
                        image[j].G = sp.PLTO[listBox1.SelectedIndex].Pal[sp.IMGO[listBox1.SelectedIndex].Image[j]].G;
                        image[j].B = sp.PLTO[listBox1.SelectedIndex].Pal[sp.IMGO[listBox1.SelectedIndex].Image[j]].B;
                    }
                    break;
                // 4x4-Texel Compressed Texture
                case 5:
                    //convert_4x4texel_b(mat.texdata, mat.width, mat.height, mat.spdata, mat.paldata, image);
                    break;
                // A5I3 Translucent Texture (5bit Alpha, 3bit Color Index)
                case 6:
                    for (int j = 0; j < pixelnum; j++)
                    {
                        int index = sp.IMGO[listBox1.SelectedIndex].Image[j] & 0x7;
                        int alpha = (sp.IMGO[listBox1.SelectedIndex].Image[j] >> 3) & 0x1f;
                        alpha = ((alpha * 4) + (alpha / 2)) << 3;
                        image[j].R = sp.PLTO[listBox1.SelectedIndex].Pal[index].R;
                        image[j].G = sp.PLTO[listBox1.SelectedIndex].Pal[index].G;
                        image[j].B = sp.PLTO[listBox1.SelectedIndex].Pal[index].B;
                        image[j].A = (byte)alpha;
                    }
                    break;
                // Direct Color Texture
                case 7:
                    for (int j = 0; j < pixelnum; j++)
                    {
                        UInt16 p = (ushort)(sp.IMGO[listBox1.SelectedIndex].Image[j * 2] + (sp.IMGO[listBox1.SelectedIndex].Image[j * 2 + 1] << 8));
                        image[j].R = (byte)(((p >> 0) & 0x1f) << 3);
                        image[j].G = (byte)(((p >> 5) & 0x1f) << 3);
                        image[j].B = (byte)(((p >> 10) & 0x1f) << 3);
                        image[j].A = (byte)(((p & 0x8000) != 0) ? 0xff : 0);
                    }
                    break;
            }
            end:*/
            Bitmap b = new Bitmap(sp.IMGO[listBox1.SelectedIndex].Width, sp.IMGO[listBox1.SelectedIndex].Height);
            try
            {
                switch (sp.IMGO[listBox1.SelectedIndex].TexFormat)
                {
                    case 1:
                        for (int j = 0; j < pixelnum; j++)
                        {
                            int index = sp.IMGO[listBox1.SelectedIndex].Image[j] & 0x1f;
                            int alpha = (sp.IMGO[listBox1.SelectedIndex].Image[j] >> 5);
                            alpha = ((alpha * 4) + (alpha / 2))*8;
                            Color c = Color.FromArgb(alpha, sp.PLTO[listBox1.SelectedIndex].Pal[index]);
                            b.SetPixel(j - ((j / (sp.IMGO[listBox1.SelectedIndex].Width)) * (sp.IMGO[listBox1.SelectedIndex].Width)), j / (sp.IMGO[listBox1.SelectedIndex].Width), c);
                        }
                        break;
                    case 2:
                        for (int j = 0; j < pixelnum; j++)
                        {
                            uint index = sp.IMGO[listBox1.SelectedIndex].Image[j / 4];
                            index = (index >> ((j % 4) << 1)) & 3;
                            b.SetPixel(j - ((j / (sp.IMGO[listBox1.SelectedIndex].Width)) * (sp.IMGO[listBox1.SelectedIndex].Width)), j / (sp.IMGO[listBox1.SelectedIndex].Width), sp.PLTO[listBox1.SelectedIndex].Pal[index]);
                        }
                        break;
                    case 3:
                        //sp.PLTO[listBox1.SelectedIndex].Pal[sp.PLTO[listBox1.SelectedIndex].Unknown] = Color.Transparent; // made palette entry 0 transparent
                        byte[] b_;
                        if (sp.IMGO[listBox1.SelectedIndex].Unknown4 == 1)
                        {
                            b_ = NSMBe4.ROM.LZ77_Decompress(sp.IMGO[listBox1.SelectedIndex].Image);
                        }
                        else
                        {
                            b_ = sp.IMGO[listBox1.SelectedIndex].Image;
                        }
                        for (int j = 0; j < pixelnum; j++)
                        {
                            uint index = b_[j / 2];
                            index = (index >> ((j % 2) << 2)) & 0x0f;
                            b.SetPixel(j - ((j / (sp.IMGO[listBox1.SelectedIndex].Width)) * (sp.IMGO[listBox1.SelectedIndex].Width)), j / (sp.IMGO[listBox1.SelectedIndex].Width), sp.PLTO[listBox1.SelectedIndex].Pal[index]);
                        }
                        b.RotateFlip(RotateFlipType.RotateNoneFlipY);
                        break;
                    case 4:
                        //if (mat.color0 != 0) mat.paldata[0] = RGBA.Transparent; // made palette entry 0 transparent
                        for (int j = 0; j < pixelnum; j++)
                        {
                            byte index = sp.IMGO[listBox1.SelectedIndex].Image[j];
                            b.SetPixel(j - ((j / (sp.IMGO[listBox1.SelectedIndex].Width)) * (sp.IMGO[listBox1.SelectedIndex].Width)), j / (sp.IMGO[listBox1.SelectedIndex].Width), sp.PLTO[listBox1.SelectedIndex].Pal[index]);
                        }
                        break;
                    case 5:
                        convert_4x4texel_b(sp.IMGO[listBox1.SelectedIndex].Image, sp.IMGO[listBox1.SelectedIndex].Width, sp.IMGO[listBox1.SelectedIndex].Height, sp.IMGO[listBox1.SelectedIndex].spData, sp.PLTO[listBox1.SelectedIndex].Pal, b);
                        b.RotateFlip(RotateFlipType.RotateNoneFlipY);
                        break;
                    case 6:
                        for (int j = 0; j < pixelnum; j++)
                        {
                            int index = sp.IMGO[listBox1.SelectedIndex].Image[j] & 0x7;
                            int alpha = (sp.IMGO[listBox1.SelectedIndex].Image[j] >> 3);// & 0x1f;
                            alpha *= 8;//((alpha * 4) + (alpha / 2)) << 5;
                            Color c = Color.FromArgb(alpha, sp.PLTO[listBox1.SelectedIndex].Pal[index]);
                            b.SetPixel(j - ((j / (sp.IMGO[listBox1.SelectedIndex].Width)) * (sp.IMGO[listBox1.SelectedIndex].Width)), j / (sp.IMGO[listBox1.SelectedIndex].Width), c);
                            //image[j].R = sp.PLTO[listBox1.SelectedIndex].Pal[index].R;
                            //image[j].G = sp.PLTO[listBox1.SelectedIndex].Pal[index].G;
                            //image[j].B = sp.PLTO[listBox1.SelectedIndex].Pal[index].B;
                            //image[j].A = (byte)alpha;
                        }
                        break;
                    case 7:
                        for (int j = 0; j < pixelnum; j++)
                        {
                            UInt16 p = (ushort)(sp.IMGO[listBox1.SelectedIndex].Image[j * 2] + (sp.IMGO[listBox1.SelectedIndex].Image[j * 2 + 1] << 8));
                            Color c = Color.FromArgb((((p & 0x8000) != 0) ? 0xff : 0), (((p >> 0) & 0x1f) << 3), (((p >> 5) & 0x1f) << 3), (((p >> 10) & 0x1f) << 3));
                            b.SetPixel(j - ((j / (sp.IMGO[listBox1.SelectedIndex].Width)) * (sp.IMGO[listBox1.SelectedIndex].Width)), j / (sp.IMGO[listBox1.SelectedIndex].Width), c);
                        }
                        break;
                }
            }
            catch
            {
                goto end2;
            }
            /*for(int y = 0; y < sp.IMGO[listBox1.SelectedIndex].Height; y++)
                for (int x = 0; x < sp.IMGO[listBox1.SelectedIndex].Width; x++)
                {
                    try
                    {
                        b.SetPixel(x, y, sp.PLTO[listBox1.SelectedIndex].Pal[(sp.IMGO[listBox1.SelectedIndex].Image[x+y*sp.IMGO[listBox1.SelectedIndex].Width] >> ((x+y*sp.IMGO[listBox1.SelectedIndex].Width % 2) << 2)) & 0x0f]);
                    }
                    catch
                    {
                        goto end2;
                    }
                }*/
            end2:
            pictureBox1.Image = b;
            //nclr_e f = new nclr_e(sp.PLTO[listBox1.SelectedIndex].Pal, false, 0);
            //f.ShowDialog();
        }
        public Bitmap RotateImg(Bitmap bmp, float angle, Color bkColor)
        {
            int w = bmp.Width;
            int h = bmp.Height;
            System.Drawing.Imaging.PixelFormat pf = default(System.Drawing.Imaging.PixelFormat);
            if (bkColor == Color.Transparent)
            {
                pf = System.Drawing.Imaging.PixelFormat.Format32bppArgb;
            }
            else
            {
                pf = bmp.PixelFormat;
            }

            Bitmap tempImg = new Bitmap(w, h, pf);
            Graphics g = Graphics.FromImage(tempImg);
            g.Clear(bkColor);
            g.DrawImageUnscaled(bmp, 1, 1);
            g.Dispose();

            System.Drawing.Drawing2D.GraphicsPath path = new System.Drawing.Drawing2D.GraphicsPath();
            path.AddRectangle(new RectangleF(0f, 0f, w, h));
            System.Drawing.Drawing2D.Matrix mtrx = new System.Drawing.Drawing2D.Matrix();
            //Using System.Drawing.Drawing2D.Matrix class 
            mtrx.Rotate(angle);
            RectangleF rct = path.GetBounds(mtrx);
            Bitmap newImg = new Bitmap(Convert.ToInt32(rct.Width), Convert.ToInt32(rct.Height), pf);
            g = Graphics.FromImage(newImg);
            g.Clear(bkColor);
            g.TranslateTransform(-rct.X, -rct.Y);
            g.RotateTransform(angle);
            g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;
            g.DrawImageUnscaled(tempImg, 0, 0);
            g.Dispose();
            tempImg.Dispose();
            return newImg;
        }
        public static bool GetBit(byte b, int bitNumber)
        {
            return(b & (1 << bitNumber)) > 0; 
        } 
        /// <summary>
        /// Convert texel.
        /// </summary>
        private bool convert_4x4texel(uint[] tex, int width, int height, UInt16[] data, Color[] pal, Bitmap rgbaOut)
        {
            int w = width / 4;
            int h = height / 4;

            // traverse 'w x h blocks' of 4x4-texel
            for (int y = 0; y < h; y++)
                for (int x = 0; x < w; x++)
                {
                    int index = y * w + x;
                    UInt32 t = tex[index];
                    UInt16 d = data[index];
                    UInt16 addr = (ushort)(d & 0x3fff);
                    UInt16 mode = (ushort)((d >> 14) & 3);

                    // traverse every texel in the 4x4 texels
                    for (int r = 0; r < 4; r++)
                        for (int c = 0; c < 4; c++)
                        {
                            int texel = (int)((t >> ((r * 4 + c) * 2)) & 3);
                            Color pixel = rgbaOut.GetPixel((x * 4 + c), (y * 4 + r));

                            switch (mode)
                            {
                                case 0:
                                    pixel = pal[(addr << 1) + texel];
                                    if (texel == 3) pixel = Color.Transparent; // make it transparent, alpha = 0
                                    break;
                                case 2:
                                    pixel = pal[(addr << 1) + texel];
                                    break;
                                case 1:
                                    switch (texel)
                                    {
                                        case 0:
                                        case 1:
                                            pixel = pal[(addr << 1) + texel];
                                            break;
                                        case 2:
                                            pixel = Color.FromArgb(0xff, (int)((pal[(addr << 1)].R + pal[(addr << 1) + 1].R) / 2L), (int)((pal[(addr << 1)].G + pal[(addr << 1) + 1].G) / 2L), (int)((pal[(addr << 1)].B + pal[(addr << 1) + 1].B) / 2L)); 
                                            break;
                                        case 3:
                                            pixel = Color.Transparent; // make it transparent, alpha = 0
                                            break;
                                    }
                                    break;
                                case 3:
                                    switch (texel)
                                    {
                                        case 0:
                                        case 1:
                                            pixel = pal[(addr << 1) + texel];
                                            break;
                                        case 2:
                                            pixel = Color.FromArgb(0xff, (int)((pal[(addr << 1)].R * 5L + pal[(addr << 1) + 1].R * 3L) / 8), (int)((pal[(addr << 1)].G * 5L + pal[(addr << 1) + 1].G * 3L) / 8), (int)((pal[(addr << 1)].B * 5L + pal[(addr << 1) + 1].B * 3L) / 8)); 
                                            break;
                                        case 3:
                                            pixel = Color.FromArgb(0xff, (int)((pal[(addr << 1)].R * 3L + pal[(addr << 1) + 1].R * 5L) / 8), (int)((pal[(addr << 1)].G * 3L + pal[(addr << 1) + 1].G * 5L) / 8), (int)((pal[(addr << 1)].B * 3L + pal[(addr << 1) + 1].B * 5L) / 8)); 
                                            break;
                                    }
                                    break;
                            }
                            rgbaOut.SetPixel((x * 4 + c), (y * 4 + r), pixel);
                            //rgbaOut[(y * 4 + r) * width + (x * 4 + c)] = pixel;
                        }
                }
            return true;
        }

        /// <summary>
        /// Convert texel (wrapper for type safety issues).
        /// </summary>
        private void convert_4x4texel_b(byte[] tex, int width, int height, byte[] data, Color[] pal, Bitmap rgbaOut)
        {
            var list1 = new List<uint>();
            for (int i = 0; i < (tex.Length + 1) / 4; ++i)
                list1.Add(LibNDSFormats.Utils.Read4BytesAsUInt32(tex, i * 4));

            var list2 = new List<UInt16>();
            for (int i = 0; i < (data.Length + 1) / 2; ++i)
                list2.Add(LibNDSFormats.Utils.Read2BytesAsUInt16(data, i * 2));
            var b = convert_4x4texel(list1.ToArray(), width, height, list2.ToArray(), pal, rgbaOut);
        }
        public static Bitmap CutImage(Image im, int width, int blockrows)
        {
            int blocksize = im.Height / blockrows;
            int blockcount = im.Width / blocksize;

            int cols = width / blocksize;
            int rows = blockcount / cols;

            Bitmap b = new Bitmap(cols * blocksize, rows * blocksize * blockrows);
            Graphics g = Graphics.FromImage(b);
            g.Clear(Color.Gray);

            Rectangle SourceRect = new Rectangle(0, 0, cols * blocksize, blocksize);
            Rectangle DestRect = new Rectangle(0, 0, cols * blocksize, blocksize);


            for (int r = 0; r < blockrows; r++)
            {
                SourceRect.Y = r * blocksize;
                for (int i = 0; i < rows; i++)
                {
                    SourceRect.X = i * cols * blocksize;
                    DestRect.Y = i * blocksize + r * rows * blocksize;

                    g.DrawImage(im, DestRect, SourceRect, GraphicsUnit.Pixel);
                }
            }

            return b;
        }

        private void toolStripButton1_Click(object sender, EventArgs e)
        {
            if (saveFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK
                && saveFileDialog1.FileName.Length > 0)
            {
                pictureBox1.Image.Save(saveFileDialog1.FileName, System.Drawing.Imaging.ImageFormat.Png);
            }
        }

        private void toolStripButton2_Click(object sender, EventArgs e)
        {
            EndianBinaryWriter ew = new EndianBinaryWriter(File.Create(file), Endianness.LittleEndian);
            ew.Write(sp.before, 0, sp.before.Length);
            ew.Write("TEXS", Encoding.ASCII, false);
            ew.Write((Int32)0);
            ew.Write((Int16)sp.Unknown1);
            ew.Write((Int16)sp.Unknown2);
            ew.Write((Int32)sp.NrTex);
            int nrTEXO = 0;
            int nrIMGO = 0;
            int nrPLTO = 0;
            for (int i = 0; i < sp.order.Count; i++)
            {
                switch (sp.order[i])
                {
                    case 0:
                        ew.Write("TEXO", Encoding.ASCII, false);
                        ew.Write((Int32)sp.TEXO[nrTEXO].Lenght);
                        ew.Write(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, 8);
                        ew.Write("NAME", Encoding.ASCII, false);
                        ew.Write((Int32)sp.TEXO[nrTEXO].Stringlength1);
                        ew.Write(sp.TEXO[nrTEXO].TexName, Encoding.ASCII, false);
                        if (sp.TEXO[nrTEXO].NameMagic2 == "NAME" || sp.IMGO[nrTEXO].TexFormat != 7)
                        {
                            ew.Write("NAME", Encoding.ASCII, false);
                            ew.Write((Int32)sp.TEXO[nrTEXO].Stringlength2);
                            ew.Write(sp.TEXO[nrTEXO].PalName, Encoding.ASCII, false);
                        }
                        nrTEXO += 1;
                        break;
                    case 1:
                        ew.Write("IMGO", Encoding.ASCII, false);
                        ew.Write((Int32)sp.IMGO[nrIMGO].Lenght);
                        ew.Write("NAME", Encoding.ASCII, false);
                        ew.Write((Int32)sp.IMGO[nrIMGO].Stringlength);
                        ew.Write(sp.IMGO[nrIMGO].Name, Encoding.ASCII, false);
                        ew.Write((Int32)sp.IMGO[nrIMGO].TexFormat);
                        ew.Write((Int16)sp.IMGO[nrIMGO].Width);
                        ew.Write((Int16)sp.IMGO[nrIMGO].Height);
                        ew.Write((Int16)sp.IMGO[nrIMGO].Unknown1);
                        ew.Write((byte)sp.IMGO[nrIMGO].Color0);
                        ew.Write((byte)sp.IMGO[nrIMGO].Unknown2);
                        ew.Write((Int32)sp.IMGO[nrIMGO].imgLength);
                        ew.Write((Int32)sp.IMGO[nrIMGO].spDataLength);
                        ew.Write((Int32)sp.IMGO[nrIMGO].Unknown4);
                        ew.Write(sp.IMGO[nrIMGO].Image, 0, sp.IMGO[nrIMGO].Image.Length);
                        if (sp.IMGO[nrIMGO].TexFormat == 5)
                        {
                            ew.Write(sp.IMGO[nrIMGO].spData, 0, sp.IMGO[nrIMGO].spData.Length);
                        }
                        nrIMGO += 1;
                        break;
                    case 2:
                        if (sp.IMGO[nrPLTO].TexFormat == 7)
                        {
                            nrPLTO += 1;
                        }
                        ew.Write("PLTO", Encoding.ASCII, false);
                        ew.Write((Int32)sp.PLTO[nrPLTO].Lenght);
                        ew.Write("NAME", Encoding.ASCII, false);
                        ew.Write((Int32)sp.PLTO[nrPLTO].Stringlength);
                        ew.Write(sp.PLTO[nrPLTO].Name, Encoding.ASCII, false);
                        ew.Write((Int32)sp.PLTO[nrPLTO].Pallength);
                        ew.Write((Int32)sp.PLTO[nrPLTO].Unknown);
                        nclr_e en = new nclr_e();
                        List<Int16> palbyte = new List<Int16>();
                        for (int j = 0; j < sp.PLTO[nrPLTO].Pal.Length; j++)
                        {
                            Color color = sp.PLTO[nrPLTO].Pal[j];
                            int nc = 0;
                            nc = en.encodeColor(color.ToArgb(), en.BGR555);
                            palbyte.Add((Int16)nc);
                        }
                        ew.Write(palbyte.ToArray(), 0, palbyte.Count);
                        nrPLTO += 1;
                        break;
                }
            }
            ew.Write(sp.beafter, 0, sp.beafter.Length);
            ew.BaseStream.Position = sp.before.Length + 4;
            ew.Write((Int32)(ew.BaseStream.Length - sp.before.Length - sp.beafter.Length - 8));
            ew.Close();
        }
        public int getClosestColor(Color c, Color[] pal)
        {
            if (c.A == 0)
                return 0;

            int bestInd = 0;
            float bestDif = ImageIndexer.colorDifferenceWithoutAlpha(pal[0], c);

            for (int i = 0; i < pal.Length; i++)
            {
                float d = ImageIndexer.colorDifferenceWithoutAlpha(pal[i], c);
                if (d < bestDif)
                {
                    bestDif = d;
                    bestInd = i;
                }
            }

            return bestInd;
        }
        private void toolStripButton3_Click(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK
                && openFileDialog1.FileName.Length > 0)
            {
                Bitmap b = new Bitmap(Bitmap.FromFile(openFileDialog1.FileName));
                if (sp.IMGO[listBox1.SelectedIndex].TexFormat == 3 || sp.IMGO[listBox1.SelectedIndex].TexFormat == 5)
                {
                    b.RotateFlip(RotateFlipType.RotateNoneFlipY);
                }
                if (sp.IMGO[listBox1.SelectedIndex].TexFormat != 5)
                {
                    Color[] c_ = new Color[0];
                    if (sp.IMGO[listBox1.SelectedIndex].TexFormat != 7) { c_ = ImageIndexer.createPaletteForImage(b, sp.PLTO[listBox1.SelectedIndex].Pal.Length); }
                    List<byte> pic = new List<byte>();
                    switch (sp.IMGO[listBox1.SelectedIndex].TexFormat)
                    {
                        case 1:
                        case 4:
                        case 6:
                            pic.AddRange(new byte[(b.Width * b.Height)]);
                            break;
                        case 2:
                        case 5:
                            pic.AddRange(new byte[(b.Width * b.Height) / 4]);
                            break;
                        case 3:
                            pic.AddRange(new byte[(b.Width * b.Height) / 2]);
                            break;
                        case 7:
                            pic.AddRange(new byte[(b.Width * b.Height) * 2]);
                            break;
                    }
                    for (int x = 0; x < b.Width; x++)
                        for (int y = 0; y < b.Height; y++)
                        {
                            Color c = b.GetPixel(x, y);
                            int i = c.ToArgb();
                            if (sp.IMGO[listBox1.SelectedIndex].TexFormat != 7) { i = getClosestColor(c, c_); }
                            pic = setPixel(x, y, i, b.Width, b.Height, sp.IMGO[listBox1.SelectedIndex].TexFormat, pic, c.A);
                        }
                    byte[] b_;
                    if (sp.IMGO[listBox1.SelectedIndex].Unknown4 == 1)
                    {
                        b_ = NSMBe4.ROM.LZ77_Compress(pic.ToArray(), false);
                    }
                    else
                    {
                        b_ = pic.ToArray();
                    }
                    sp.IMGO[listBox1.SelectedIndex].Image = b_;
                    sp.IMGO[listBox1.SelectedIndex].Height = (Int16)b.Height;
                    sp.IMGO[listBox1.SelectedIndex].Width = (Int16)b.Width;
                    sp.IMGO[listBox1.SelectedIndex].imgLength = b_.Length;
                    sp.IMGO[listBox1.SelectedIndex].Lenght = 8 + sp.IMGO[listBox1.SelectedIndex].Stringlength + 0x10 + sp.IMGO[listBox1.SelectedIndex].spDataLength + sp.IMGO[listBox1.SelectedIndex].imgLength;
                    if (sp.IMGO[listBox1.SelectedIndex].TexFormat != 7) { sp.PLTO[listBox1.SelectedIndex].Pal = c_; }
                    listBox1.SetSelected(listBox1.SelectedIndex, true);
                }
                else
                {
                    BackgroundWorker bw = new BackgroundWorker();
                    bw.WorkerReportsProgress = true;
                    bw.WorkerSupportsCancellation = true;
                    bw.DoWork += new DoWorkEventHandler(tex4x4);
                    bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
                    bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
                    bw.RunWorkerAsync(listBox1.SelectedIndex);
                    bwr = bw;
                    toolStripButton4.Enabled = true;
                    /*NSMBe4.NSBMD.ImageTexeler it = new NSMBe4.NSBMD.ImageTexeler(b, sp.PLTO[listBox1.SelectedIndex].Pal.Length / 4);
                    sp.IMGO[listBox1.SelectedIndex].Image = it.texdata;
                    sp.IMGO[listBox1.SelectedIndex].spData = it.f5data;
                    sp.IMGO[listBox1.SelectedIndex].Height = (Int16)b.Height;
                    sp.IMGO[listBox1.SelectedIndex].Width = (Int16)b.Width;
                    sp.IMGO[listBox1.SelectedIndex].imgLength = it.texdata.Length;
                    sp.IMGO[listBox1.SelectedIndex].spDataLength = it.f5data.Length;
                    sp.IMGO[listBox1.SelectedIndex].Lenght = 8 + sp.IMGO[listBox1.SelectedIndex].Stringlength + 0x10 + sp.IMGO[listBox1.SelectedIndex].spDataLength + sp.IMGO[listBox1.SelectedIndex].imgLength;
                    sp.PLTO[listBox1.SelectedIndex].Pal = it.finalPalette;*/
                    listBox1.SetSelected(listBox1.SelectedIndex, true);
                }
            }
        }
        public List<byte> setPixel(int x, int y, int c, int width, int height, int format, List<byte> pic, int alpha)
        {
            List<byte> pic2 = pic;
            if (x < 0 || x >= width) return null;
            if (y < 0 || y >= height) return null;
            if (format == 1)
            {
                c &= 0x1F;
                c |= alpha & (~0x1F);
            }
            if (format == 6)
            {
                c &= 0x07;
                c |= alpha & (~0x07);
            }

            pic2 = setPixelVal(x, y, c, width, bpp[format], pic);
            return pic2;
        }
        int[] bpp = {0, 8, 2, 4, 8, 2, 8, 16};
        private List<byte> setPixelVal(int x, int y, int v, int width, int bpp, List<byte> pic)
        {
            List<byte> pic2 = pic;
            int i = x + y * width;
            if (bpp == 8) { pic2[i] = (byte)v; return pic2; }
            else if (bpp == 16)
            {
                //pic2[i * 2] = (byte)(v & 0xFF);
                //pic2[(i * 2) + 1] = (byte)((v >> 8) & 0xFF);
                nclr_e en = new nclr_e();
                Int16 b = (short)en.encodeColor(v, en.BGR555);
                b |= (short)((Color.FromArgb(v).A == 0 ? ~0x8000 : 0x8000));
                pic2[i * 2] = BitConverter.GetBytes(b)[0];
                pic2[(i * 2)+1] = BitConverter.GetBytes(b)[1];
                return pic2;
            }

            else if (bpp == 4)
            {
                int res = pic2[i / 2];
                res &= ~(0xF << ((i % 2) * 4));
                res |= (v & 0xF) << ((i % 2) * 4);
                pic2[i / 2] = (byte)res;
            }

            else if (bpp == 2)
            {
                int res = pic2[i / 4];
                res &= ~(0xF << ((i % 4) * 2));
                res |= (v & 0xF) << ((i % 4) * 2);
                pic2[i / 4] = (byte)res;
            }
            else
            {
                throw new Exception("Unsupported BPP Value: " + bpp);
            }
            return pic2;
        }

        private void toolStripMenuItem2_Click(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK
                && openFileDialog1.FileName.Length > 0)
            {
                Bitmap b = new Bitmap(Bitmap.FromFile(openFileDialog1.FileName));
                    Color[] c_ = ImageIndexer.createPaletteForImage(b, 24);
                    List<byte> pic = new List<byte>();
                    pic.AddRange(new byte[(b.Width * b.Height)]);
                    for (int x = 0; x < b.Width; x++)
                        for (int y = 0; y < b.Height; y++)
                        {
                            Color c = b.GetPixel(x, y);
                            int i = c.ToArgb();
                            i = getClosestColor(c, c_);
                            pic = setPixel(x, y, i, b.Width, b.Height, 1, pic, c.A);
                        }
                    byte[] b_;
                    if (sp.IMGO[listBox1.SelectedIndex].Unknown4 == 1)
                    {
                        b_ = NSMBe4.ROM.LZ77_Compress(pic.ToArray(), false);
                    }
                    else
                    {
                        b_ = pic.ToArray();
                    }
                    sp.IMGO[listBox1.SelectedIndex].Image = b_;
                    sp.IMGO[listBox1.SelectedIndex].spDataLength = 0;
                    sp.IMGO[listBox1.SelectedIndex].spData = new byte[0];
                    sp.IMGO[listBox1.SelectedIndex].TexFormat = 1;
                    sp.IMGO[listBox1.SelectedIndex].Height = (Int16)b.Height;
                    sp.IMGO[listBox1.SelectedIndex].Width = (Int16)b.Width;
                    sp.IMGO[listBox1.SelectedIndex].imgLength = b_.Length;
                    sp.IMGO[listBox1.SelectedIndex].Lenght = 8 + sp.IMGO[listBox1.SelectedIndex].Stringlength + 0x10 + sp.IMGO[listBox1.SelectedIndex].spDataLength + sp.IMGO[listBox1.SelectedIndex].imgLength;
                    sp.PLTO[listBox1.SelectedIndex].Pal = c_;
                    sp.PLTO[listBox1.SelectedIndex].Pallength = c_.Length * 2;
                    sp.PLTO[listBox1.SelectedIndex].Lenght = 8 + sp.PLTO[listBox1.SelectedIndex].Stringlength + 0x8 + sp.PLTO[listBox1.SelectedIndex].Pallength;
                    listBox1.SetSelected(listBox1.SelectedIndex, true);
                }
        }

        private void colorPaletteTextureToolStripMenuItem2_Click(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK
                && openFileDialog1.FileName.Length > 0)
            {
                Bitmap b = new Bitmap(Bitmap.FromFile(openFileDialog1.FileName));
                Color[] c_ = ImageIndexer.createPaletteForImage(b, 4);
                List<byte> pic = new List<byte>();
                pic.AddRange(new byte[(b.Width * b.Height) / 4]);
                for (int x = 0; x < b.Width; x++)
                    for (int y = 0; y < b.Height; y++)
                    {
                        Color c = b.GetPixel(x, y);
                        int i = c.ToArgb();
                        i = getClosestColor(c, c_);
                        pic = setPixel(x, y, i, b.Width, b.Height, 2, pic, c.A);
                    }
                byte[] b_;
                if (sp.IMGO[listBox1.SelectedIndex].Unknown4 == 1)
                {
                    b_ = NSMBe4.ROM.LZ77_Compress(pic.ToArray(), false);
                }
                else
                {
                    b_ = pic.ToArray();
                }
                sp.IMGO[listBox1.SelectedIndex].Image = b_;
                sp.IMGO[listBox1.SelectedIndex].TexFormat = 2;
                sp.IMGO[listBox1.SelectedIndex].spDataLength = 0;
                sp.IMGO[listBox1.SelectedIndex].spData = new byte[0];
                sp.IMGO[listBox1.SelectedIndex].Height = (Int16)b.Height;
                sp.IMGO[listBox1.SelectedIndex].Width = (Int16)b.Width;
                sp.IMGO[listBox1.SelectedIndex].imgLength = b_.Length;
                sp.IMGO[listBox1.SelectedIndex].Lenght = 8 + sp.IMGO[listBox1.SelectedIndex].Stringlength + 0x10 + sp.IMGO[listBox1.SelectedIndex].spDataLength + sp.IMGO[listBox1.SelectedIndex].imgLength;
                sp.PLTO[listBox1.SelectedIndex].Pal = c_;
                sp.PLTO[listBox1.SelectedIndex].Pallength = c_.Length * 2;
                sp.PLTO[listBox1.SelectedIndex].Lenght = 8 + sp.PLTO[listBox1.SelectedIndex].Stringlength + 0x8 + sp.PLTO[listBox1.SelectedIndex].Pallength;
                listBox1.SetSelected(listBox1.SelectedIndex, true);
            }
        }

        private void colorPaletteTextureToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK
                && openFileDialog1.FileName.Length > 0)
            {
                Bitmap b = new Bitmap(Bitmap.FromFile(openFileDialog1.FileName));
                b.RotateFlip(RotateFlipType.RotateNoneFlipY);
                Color[] c_ = ImageIndexer.createPaletteForImage(b, 16);
                List<byte> pic = new List<byte>();
                pic.AddRange(new byte[(b.Width * b.Height) / 2]);
                for (int x = 0; x < b.Width; x++)
                    for (int y = 0; y < b.Height; y++)
                    {
                        Color c = b.GetPixel(x, y);
                        int i = c.ToArgb();
                        i = getClosestColor(c, c_);
                        pic = setPixel(x, y, i, b.Width, b.Height, 3, pic, c.A);
                    }
                byte[] b_;
                if (sp.IMGO[listBox1.SelectedIndex].Unknown4 == 1)
                {
                    b_ = NSMBe4.ROM.LZ77_Compress(pic.ToArray(), false);
                }
                else
                {
                    b_ = pic.ToArray();
                }
                sp.IMGO[listBox1.SelectedIndex].Image = b_;
                sp.IMGO[listBox1.SelectedIndex].TexFormat = 3;
                sp.IMGO[listBox1.SelectedIndex].spDataLength = 0;
                sp.IMGO[listBox1.SelectedIndex].spData = new byte[0];
                sp.IMGO[listBox1.SelectedIndex].Height = (Int16)b.Height;
                sp.IMGO[listBox1.SelectedIndex].Width = (Int16)b.Width;
                sp.IMGO[listBox1.SelectedIndex].imgLength = b_.Length;
                sp.IMGO[listBox1.SelectedIndex].Lenght = 8 + sp.IMGO[listBox1.SelectedIndex].Stringlength + 0x10 + sp.IMGO[listBox1.SelectedIndex].spDataLength + sp.IMGO[listBox1.SelectedIndex].imgLength;
                sp.PLTO[listBox1.SelectedIndex].Pal = c_;
                sp.PLTO[listBox1.SelectedIndex].Pallength = c_.Length * 2;
                sp.PLTO[listBox1.SelectedIndex].Lenght = 8 + sp.PLTO[listBox1.SelectedIndex].Stringlength + 0x8 + sp.PLTO[listBox1.SelectedIndex].Pallength;
                listBox1.SetSelected(listBox1.SelectedIndex, true);
            }
        }

        private void colorPaletteTextureToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK
                && openFileDialog1.FileName.Length > 0)
            {
                Bitmap b = new Bitmap(Bitmap.FromFile(openFileDialog1.FileName));
                Color[] c_ = ImageIndexer.createPaletteForImage(b, 256);
                List<byte> pic = new List<byte>();
                pic.AddRange(new byte[(b.Width * b.Height)]);
                for (int x = 0; x < b.Width; x++)
                    for (int y = 0; y < b.Height; y++)
                    {
                        Color c = b.GetPixel(x, y);
                        int i = c.ToArgb();
                        i = getClosestColor(c, c_);
                        pic = setPixel(x, y, i, b.Width, b.Height, 4, pic, c.A);
                    }
                byte[] b_;
                if (sp.IMGO[listBox1.SelectedIndex].Unknown4 == 1)
                {
                    b_ = NSMBe4.ROM.LZ77_Compress(pic.ToArray(), false);
                }
                else
                {
                    b_ = pic.ToArray();
                }
                sp.IMGO[listBox1.SelectedIndex].Image = b_;
                sp.IMGO[listBox1.SelectedIndex].TexFormat = 4;
                sp.IMGO[listBox1.SelectedIndex].spDataLength = 0;
                sp.IMGO[listBox1.SelectedIndex].spData = new byte[0];
                sp.IMGO[listBox1.SelectedIndex].Height = (Int16)b.Height;
                sp.IMGO[listBox1.SelectedIndex].Width = (Int16)b.Width;
                sp.IMGO[listBox1.SelectedIndex].imgLength = b_.Length;
                sp.IMGO[listBox1.SelectedIndex].Lenght = 8 + sp.IMGO[listBox1.SelectedIndex].Stringlength + 0x10 + sp.IMGO[listBox1.SelectedIndex].spDataLength + sp.IMGO[listBox1.SelectedIndex].imgLength;
                sp.PLTO[listBox1.SelectedIndex].Pal = c_;
                sp.PLTO[listBox1.SelectedIndex].Pallength = c_.Length * 2;
                sp.PLTO[listBox1.SelectedIndex].Lenght = 8 + sp.PLTO[listBox1.SelectedIndex].Stringlength + 0x8 + sp.PLTO[listBox1.SelectedIndex].Pallength;
                listBox1.SetSelected(listBox1.SelectedIndex, true);
            }
        }

        private void x4TexelCompressedTextureToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK
                && openFileDialog1.FileName.Length > 0)
            {
                BackgroundWorker bw = new BackgroundWorker();
                bw.WorkerReportsProgress = true;
                bw.WorkerSupportsCancellation = true;
                bw.DoWork +=new DoWorkEventHandler(tex4x4);
                bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
                bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
                bw.RunWorkerAsync(listBox1.SelectedIndex);
                bwr = bw;
                toolStripButton4.Enabled = true;
            }
        }

        void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            listBox1.SetSelected((int)e.Result, true);
            bwr = null;
            toolStripButton4.Enabled = false;
        }

        void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            toolStripProgressBar1.Value = e.ProgressPercentage;
            toolStripLabel1.Text = (string)e.UserState;
        }

        void tex4x4(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker bw = (BackgroundWorker)sender;
            bw.ReportProgress(0);
            Bitmap b = new Bitmap(Bitmap.FromFile(openFileDialog1.FileName));
            if (((b.Height > 512 && b.Width > 1024) || (b.Height > 1024 && b.Width > 512)) == false)
            {
                bw.ReportProgress(10);
                b.RotateFlip(RotateFlipType.RotateNoneFlipY);
                NSMBe4.NSBMD.ImageTexeler it = new NSMBe4.NSBMD.ImageTexeler(b, 1024, ref bw);
                if (bw.CancellationPending != true)
                {
                    int SelectedIndex = (int)e.Argument;
                    sp.IMGO[SelectedIndex].Image = it.texdata;
                    sp.IMGO[SelectedIndex].spData = it.f5data;
                    sp.IMGO[SelectedIndex].TexFormat = 5;
                    sp.IMGO[SelectedIndex].Height = (Int16)b.Height;
                    sp.IMGO[SelectedIndex].Width = (Int16)b.Width;
                    sp.IMGO[SelectedIndex].imgLength = it.texdata.Length;
                    sp.IMGO[SelectedIndex].spDataLength = it.f5data.Length;
                    sp.IMGO[SelectedIndex].Lenght = 8 + sp.IMGO[SelectedIndex].Stringlength + 0x10 + sp.IMGO[SelectedIndex].spDataLength + sp.IMGO[SelectedIndex].imgLength;
                    sp.PLTO[SelectedIndex].Pal = it.finalPalette;
                    sp.PLTO[SelectedIndex].Pallength = it.finalPalette.Length * 2;
                    sp.PLTO[SelectedIndex].Lenght = 8 + sp.PLTO[SelectedIndex].Stringlength + 0x8 + sp.PLTO[SelectedIndex].Pallength;
                    bw.ReportProgress(100);
                }
            }
            else
            {
                bw.ReportProgress(0, "Error");
                MessageBox.Show("The maximum size for 4x4-Texel Compressed Textures is 1024x512 or 512x1024.");
            }
                e.Result = e.Argument;
        }

        private void a5I3TranslucentTextureToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK
                && openFileDialog1.FileName.Length > 0)
            {
                Bitmap b = new Bitmap(Bitmap.FromFile(openFileDialog1.FileName));
                Color[] c_ = ImageIndexer.createPaletteForImage(b, 8);
                List<byte> pic = new List<byte>();
                pic.AddRange(new byte[(b.Width * b.Height)]);
                for (int x = 0; x < b.Width; x++)
                    for (int y = 0; y < b.Height; y++)
                    {
                        Color c = b.GetPixel(x, y);
                        int i = c.ToArgb();
                        i = getClosestColor(c, c_);
                        pic = setPixel(x, y, i, b.Width, b.Height, 6, pic, c.A);
                    }
                byte[] b_;
                if (sp.IMGO[listBox1.SelectedIndex].Unknown4 == 1)
                {
                    b_ = NSMBe4.ROM.LZ77_Compress(pic.ToArray(), false);
                }
                else
                {
                    b_ = pic.ToArray();
                }
                sp.IMGO[listBox1.SelectedIndex].Image = b_;
                sp.IMGO[listBox1.SelectedIndex].TexFormat = 6;
                sp.IMGO[listBox1.SelectedIndex].spDataLength = 0;
                sp.IMGO[listBox1.SelectedIndex].spData = new byte[0];
                sp.IMGO[listBox1.SelectedIndex].Height = (Int16)b.Height;
                sp.IMGO[listBox1.SelectedIndex].Width = (Int16)b.Width;
                sp.IMGO[listBox1.SelectedIndex].imgLength = b_.Length;
                sp.IMGO[listBox1.SelectedIndex].Lenght = 8 + sp.IMGO[listBox1.SelectedIndex].Stringlength + 0x10 + sp.IMGO[listBox1.SelectedIndex].spDataLength + sp.IMGO[listBox1.SelectedIndex].imgLength;
                sp.PLTO[listBox1.SelectedIndex].Pal = c_;
                sp.PLTO[listBox1.SelectedIndex].Pallength = c_.Length * 2;
                sp.PLTO[listBox1.SelectedIndex].Lenght = 8 + sp.PLTO[listBox1.SelectedIndex].Stringlength + 0x8 + sp.PLTO[listBox1.SelectedIndex].Pallength;
                listBox1.SetSelected(listBox1.SelectedIndex, true);
            }
        }

        private void directColorTextureToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK
            && openFileDialog1.FileName.Length > 0)
            {
                BackgroundWorker bw = new BackgroundWorker();
                bw.WorkerReportsProgress = true;
                bw.WorkerSupportsCancellation = true;
                bw.DoWork += new DoWorkEventHandler(fullColor);
                bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
                bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
                bw.RunWorkerAsync(listBox1.SelectedIndex);
                bwr = bw;
                toolStripButton4.Enabled = true;
            }
        }

        void fullColor(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker bw = (BackgroundWorker)sender;
            bw.ReportProgress(0);
            Bitmap b = new Bitmap(Bitmap.FromFile(openFileDialog1.FileName));
            bw.ReportProgress(25);
            List<byte> pic = new List<byte>();
            pic.AddRange(new byte[(b.Width * b.Height) * 2]);
            float add = 75f / (float)(b.Width * b.Height);
            float Progress = 25;
            for (int x = 0; x < b.Width; x++)
                for (int y = 0; y < b.Height; y++)
                {
                    Color c = b.GetPixel(x, y);
                    int i = c.ToArgb();
                    pic = setPixel(x, y, i, b.Width, b.Height, 7, pic, c.A);
                    Progress += add;
                    bw.ReportProgress((int)Progress);
                }
            byte[] b_;
            int SelectedIndex = (int)e.Argument;
            if (sp.IMGO[SelectedIndex].Unknown4 == 1)
            {
                b_ = NSMBe4.ROM.LZ77_Compress(pic.ToArray(), false);
            }
            else
            {
                b_ = pic.ToArray();
            }
            sp.IMGO[SelectedIndex].Image = b_;
            sp.IMGO[SelectedIndex].TexFormat = 7;
            sp.IMGO[SelectedIndex].spDataLength = 0;
            sp.IMGO[SelectedIndex].spData = new byte[0];
            sp.IMGO[SelectedIndex].Height = (Int16)b.Height;
            sp.IMGO[SelectedIndex].Width = (Int16)b.Width;
            sp.IMGO[SelectedIndex].imgLength = b_.Length;
            sp.IMGO[SelectedIndex].Lenght = 8 + sp.IMGO[SelectedIndex].Stringlength + 0x10 + sp.IMGO[SelectedIndex].spDataLength + sp.IMGO[SelectedIndex].imgLength;
            bw.ReportProgress(100);
            e.Result = e.Argument;
        }

        private void toolStripProgressBar2_Click(object sender, EventArgs e)
        {

        }

        private void toolStripButton4_Click(object sender, EventArgs e)
        {
            if (bwr != null)
            {
                bwr.CancelAsync();
            }
        }
    }
}
